// -------------------------------
// projects/c++/3n+1/TestCollatz.h
// Copyright (C) 2009
// Glenn P. Downing
// -------------------------------

#ifndef TestCollatz_h
#define TestCollatz_h

// --------
// includes
// --------

#include <sstream> // istringtstream, ostringstream
#include <string>  // ==

#include "cppunit/TestFixture.h"			 // TestFixture
#include "cppunit/extensions/HelperMacros.h" // CPPUNIT_TEST, CPPUNIT_TEST_SUITE, CPPUNIT_TEST_SUITE_END
#include "cache.h" // MAX_CACHE

extern unsigned int cache[CACHE_SIZE + 1];

using namespace CppUnit;

// -----------
// TestCollatz
// -----------

struct TestCollatz : TestFixture {
	// ----
	// read
	// ----

	void test_read() 
	{
		std::istringstream in("1 10\n");
		bool b = read(in);
		CPPUNIT_ASSERT(b == true);
		CPPUNIT_ASSERT(i ==	1);
		CPPUNIT_ASSERT(j ==   10);
	}

	// ----
	// eval
	// ----

	void test_eval1()
	{
		i =  1;
		j = 10;
		v =  0;
		eval();
		CPPUNIT_ASSERT(v == 20);
	}

	void test_eval2 ()
	{
		i = 100;
		j = 200;
		v =   0;
		eval();
		CPPUNIT_ASSERT(v == 125);
	}

	void test_eval3()
	{
		i = 201;
		j = 210;
		v =   0;
		eval();
		CPPUNIT_ASSERT(v == 89);
	}

	void test_eval4()
	{
		i =  900;
		j = 1000;
		v =	0;
		eval();
		CPPUNIT_ASSERT(v == 174);
	}

	void test_eval_backwards()
	{
		i = 10;
		j =  1;
		v =  0;
		eval();
		CPPUNIT_ASSERT(v == 20);
	}

	// ------------
	// cache_lookup
	// ------------

	void test_cache_lookup_max_bounds()
	{
		cache[CACHE_SIZE] = 5;
		CPPUNIT_ASSERT(cache_lookup(CACHE_SIZE) == 0);
	}

	void test_cache_lookup_store_fetch()
	{
		cache[5] = 0;
		cache_store(5, 100);
		CPPUNIT_ASSERT(cache_lookup(5) == 100);
	}
	

	// -----------
	// cache_store
	// -----------
	void test_cache_store_max_bounds()
	{
		cache[CACHE_SIZE] = 0;
		cache_store(CACHE_SIZE, 5);
		CPPUNIT_ASSERT(cache[CACHE_SIZE] == 0);
	}

	// -------
	// is_even
	// -------
	void test_is_even()
	{
		CPPUNIT_ASSERT(is_even(1) == false);
		CPPUNIT_ASSERT(is_even(2) == true);
		CPPUNIT_ASSERT(is_even(0) == true);
	}
	
	// ------------
	// cycle_length
	// ------------
	void test_cycle_length_1()
	{
		CPPUNIT_ASSERT(cycle_length(1) == 1);
	}


	void test_cycle_length_2()
	{
		CPPUNIT_ASSERT(cycle_length(2) == 2);
	}

	void test_cycle_length_3()
	{
		CPPUNIT_ASSERT(cycle_length(3) == 8);
	}

	void test_cycle_length_10()
	{
		CPPUNIT_ASSERT(cycle_length(10) == 7);
	}

	void test_cycle_length_64()
	{
		CPPUNIT_ASSERT(cycle_length(64) == 7);
	}

	void test_cycle_length_97()
	{
		CPPUNIT_ASSERT(cycle_length(97) == 119);
	}

	// -----
	// print
	// -----

	void test_print () {
		i =  1;
		j = 10;
		v = 20;
		std::ostringstream out;
		print(out);
		CPPUNIT_ASSERT(out.str() == "1 10 20\n");
	}

	// -----
	// suite
	// -----

	CPPUNIT_TEST_SUITE(TestCollatz);
	CPPUNIT_TEST(test_read);
	CPPUNIT_TEST(test_eval1);
	CPPUNIT_TEST(test_eval2);
	CPPUNIT_TEST(test_eval3);
	CPPUNIT_TEST(test_eval4);
	CPPUNIT_TEST(test_eval_backwards);
	CPPUNIT_TEST(test_cache_lookup_max_bounds);
	CPPUNIT_TEST(test_cache_lookup_store_fetch);
	CPPUNIT_TEST(test_cache_store_max_bounds);
	CPPUNIT_TEST(test_is_even);
	CPPUNIT_TEST(test_cycle_length_1);
	CPPUNIT_TEST(test_cycle_length_2);
	CPPUNIT_TEST(test_cycle_length_3);
	CPPUNIT_TEST(test_cycle_length_10);
	CPPUNIT_TEST(test_cycle_length_64);
	CPPUNIT_TEST(test_cycle_length_97);
	CPPUNIT_TEST(test_print);

	CPPUNIT_TEST_SUITE_END();
};

#endif // TestCollatz_h


